﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Tools.MAME;

namespace GameListEditor
{
    /// <summary> Filter form. </summary>
    public partial class FormAdvFilter : Form
    {
        #region Constants

        private const int LESS_THAN_OR_EQUAL = 0;
        private const int GREATER_THAN_OR_EQUAL = 1;
        private const int EQUAL_TO = 2;
        private const int NOT_EQUAL_TO = 3;

        #endregion

        #region Properties

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Gets the filter. </summary>
        /// <value> The filter. </value>
        ///-------------------------------------------------------------------------------------------------
        public DatabaseFilter Filter
        {
            get
            {
                DatabaseFilter filter = new DatabaseFilter();

                // Flags
                filter.ExcludeNonPlayable = chkExcludeNonPlayable.Checked;
                filter.ExcludeMature = chkExcludeMature.Checked;
                filter.ExcludeBootlegs = chkExcludeBootlegs.Checked;
                filter.ExcludeHacks = chkExcludeHacks.Checked;
                filter.ExcludeCHDs = chkExcludeCHDRequired.Checked;

                // Player Count
                int? minPlayerCount = null;
                if (chkMinPlayerCount.Checked)
                    minPlayerCount = Convert.ToInt32(Math.Round(spnMinPlayerCount.Value));

                int? maxPlayerCount = null;
                if (chkMaxPlayerCount.Checked)
                    maxPlayerCount = Convert.ToInt32(Math.Round(spnMaxPlayerCount.Value));

                filter.AddSmartPlayerCountFilter(minPlayerCount, maxPlayerCount);

                // Button Count
                if (chkMaxButtonCount.Checked)
                    filter.AddSmartButtonCountFilter(Convert.ToInt32(Math.Round(spnMaxButtonCount.Value)));

                // Year
                if (rbYearSimple.Checked)
                {
                    switch (cmbYearCondition.SelectedIndex)
                    {
                        case LESS_THAN_OR_EQUAL:
                            filter.AddYearFilter(Convert.ToInt32(Math.Round(spnExactYear.Value)), Condition.LessThanOrEqual, false);
                            break;

                        case GREATER_THAN_OR_EQUAL:
                            filter.AddYearFilter(Convert.ToInt32(Math.Round(spnExactYear.Value)), Condition.GreaterThanOrEqual, false);
                            break;

                        case EQUAL_TO:
                            filter.AddYearFilter(Convert.ToInt32(Math.Round(spnExactYear.Value)), Condition.Equal, false);
                            break;

                        case NOT_EQUAL_TO:
                            filter.AddYearFilter(Convert.ToInt32(Math.Round(spnExactYear.Value)), Condition.NotEqual, false);
                            break;

                        default:
                            throw new NotImplementedException();
                    }
                }
                else if (rbYearBetween.Checked)
                {
                    filter.AddYearFilter(Convert.ToInt32(Math.Round(spnYearMin.Value)), Condition.GreaterThanOrEqual, false);
                    filter.AddYearFilter(Convert.ToInt32(Math.Round(spnYearMax.Value)), Condition.LessThanOrEqual, false);
                }

                // Controls
                if (lstControls.CheckedItems.Count > 0)
                    for (int i = 0; i < lstControls.Items.Count; i++)
                        if (!lstControls.GetItemChecked(i))
                            filter.AddControlExclude((String)lstControls.Items[i]);

                // Categories
                if (lstCategories.CheckedItems.Count > 0)
                    for (int i = 0; i < lstCategories.Items.Count; i++)
                        if (!lstCategories.GetItemChecked(i))
                            filter.AddCategoryExclude((String)lstCategories.Items[i]);

                // Region
                if (rbSpecificRegion.Checked)
                {
                    if (lstRegions.CheckedItems.Count <= 0)
                        throw new Exception("One or more regions must be selected.");

                    filter.FilterMode = IntelligentFilterMode.Region;
                    for (int i = 0; i < lstRegions.CheckedItems.Count; i++)
                        filter.AddRegion((String)lstRegions.CheckedItems[i]);
                }
                else if (rbIntelligentRegionOnePer.Checked)
                {
                    if (lstRegions.CheckedItems.Count != 1)
                        throw new Exception("One region must be selected.");

                    filter.FilterMode = IntelligentFilterMode.OnePerWithRegionHint;
                    filter.AddRegion((String)lstRegions.CheckedItems[0]);
                }

                return filter;
            }
        }

        #endregion

        #region Constructor(s)

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Constructor. </summary>
        /// <param name="categories"> The available categories. </param>
        /// <param name="controls">   The available controls. </param>
        /// <param name="regions">    The available regions. </param>
        ///-------------------------------------------------------------------------------------------------
        public FormAdvFilter(ICollection<String> categories, ICollection<String> controls,
            ICollection<String> regions)
        {
            InitializeComponent();

            lstCategories.Items.Clear();
            if (categories != null)
                foreach (String category in categories)
                    lstCategories.Items.Add(category);

            lstControls.Items.Clear();
            if (controls != null)
                foreach (String control in controls)
                    lstControls.Items.Add(control);

            lstRegions.Items.Clear();
            if (regions != null)
                foreach (String region in regions)
                    lstRegions.Items.Add(region);

            cmbYearCondition.SelectedIndex = LESS_THAN_OR_EQUAL;

            UpdateGui();
        }

        #endregion

        #region Private Helper Methods

        /// <summary> Updates the graphical user interface. </summary>
        private void UpdateGui()
        {
            if (this.InvokeRequired)
                this.Invoke(new MethodInvoker(delegate { UpdateGui(); }));
            else
            {
                // Year
                cmbYearCondition.Enabled = rbYearSimple.Checked;
                spnExactYear.Enabled = rbYearSimple.Checked;
                spnYearMin.Enabled = rbYearBetween.Checked;
                spnYearMax.Enabled = rbYearBetween.Checked;

                // General
                spnMaxPlayerCount.Enabled = chkMaxPlayerCount.Checked;
                spnMinPlayerCount.Enabled = chkMinPlayerCount.Checked;
                spnMaxButtonCount.Enabled = chkMaxButtonCount.Checked;

                // Region
                lstRegions.Enabled = !rbRegionOff.Checked;
            }
        }

        #endregion

        #region Control Event Handlers

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Event handler. Called by FormAdvFilter for form closing events. </summary>
        /// <param name="sender"> Source of the event. </param>
        /// <param name="e">      Form closing event information. </param>
        ///-------------------------------------------------------------------------------------------------
        private void FormAdvFilter_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (DialogResult == System.Windows.Forms.DialogResult.OK)
            {
                if (rbSpecificRegion.Checked)
                {
                    if (lstRegions.CheckedItems.Count <= 0)
                    {
                        MessageBox.Show("One or more regions must be selected.");
                        e.Cancel = true;
                    }
                }
                else if (rbIntelligentRegionOnePer.Checked)
                {
                    if (lstRegions.CheckedItems.Count != 1)
                    {
                        MessageBox.Show("One region must be selected.");
                        e.Cancel = true;
                    }
                }
            }
        }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Event handler. Called by generic for changed events. </summary>
        /// <param name="sender"> Source of the event. </param>
        /// <param name="e">      Event information. </param>
        ///-------------------------------------------------------------------------------------------------
        private void generic_Changed(object sender, EventArgs e)
        {
            try
            {
                UpdateGui();
            }
            catch
            { }
        }

        #endregion        
    }
}
